package pl.umk.mat.fred.unicore.urc.storagemanagement.actions.findNavigation;

import java.util.Arrays;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.ui.PlatformUI;

import pl.umk.mat.fred.unicore.urc.storagemanagement.actions.FindAction.SearchResult;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.CatalogNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.GridNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.Node;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.RootNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.tree.nodes.StorageNode;
import pl.umk.mat.fred.unicore.urc.storagemanagement.views.StorageBrowserView;

public class CommonTools {

	public static boolean trySelectTreeNode(Action action, StorageBrowserView view, List<String> listOfMulticatalogs, SearchResult result) {
		System.out.println("Try select " + result.getPath());
		RootNode rn = view.getInitalInput();
		GridNode gn = (GridNode) rn.getChildren().get(0);
		StorageNode sn = null;
		for (Node n : gn.getChildren()) {
			if (((StorageNode) n).getStorage().equals(result.getStorage())) {
				sn = (StorageNode) n;
				break;
			}
		}
		if (sn == null) {
			return false;
		}
		goDeeper(action, view, listOfMulticatalogs, result, sn, result.getPath().split("/"), 1, false);
		return false;
  }
	
	private static void goDeeper(final Action action, final StorageBrowserView view, final List<String> listOfMulticatalogs, final SearchResult result, final Node parent, final String[] pathElements, final int pointer, boolean refreshTree) {
		if (pathElements.length > pointer) {
			Node node = null;
			for (Node n : parent.getChildren()) {
				if (n.getPath().endsWith("/" + pathElements[pointer])) {
					node = n;
					break;
				}
			}
			boolean givingUpControl = false;
			if (node == null) {
				// There is any matching node, refresh needed
				if (refreshTree) {
        	view.getDoubleClickAction().runOnThisThread(parent);
        	node = null;
        	for (Node n : parent.getChildren()) {
  					if (n.getPath().endsWith("/" + pathElements[pointer])) {
  						node = n;
  						break;
  					}
  				}
        	if (pathElements.length - 1 == pointer) {
    				setSelectionOnTree(action, view, listOfMulticatalogs, result, node, refreshTree);
    			} else {
    				goDeeper(action, view, listOfMulticatalogs, result, node, pathElements, pointer + 1, refreshTree);
    			}
				} else {
					Job job = new Job("Next search result") {
						@Override
	          protected IStatus run(IProgressMonitor monitor) {
		          try {
		          	monitor.beginTask("", IProgressMonitor.UNKNOWN);
		          	boolean refreshTree = true;
		          	view.getDoubleClickAction().runOnThisThread(parent);
		          	Node node = null;
		          	for (Node n : parent.getChildren()) {
		    					if (n.getPath().endsWith("/" + pathElements[pointer])) {
		    						node = n;
		    						break;
		    					}
		    				}
		          	if (pathElements.length - 1 == pointer) {
		      				setSelectionOnTree(action, view, listOfMulticatalogs, result, node, refreshTree);
		      				return Status.OK_STATUS;
		      			} else {
		      				goDeeper(action, view, listOfMulticatalogs, result, node, pathElements, pointer + 1, refreshTree);
		      				return Status.OK_STATUS;
		      			}
		          } finally {
		          	monitor.done();
		          }
	          }
					};
					job.schedule();
					givingUpControl = true;
				}
			}
			if (!givingUpControl) {
				if (pathElements.length - 1 == pointer) {
					setSelectionOnTree(action, view, listOfMulticatalogs, result, node, refreshTree);
				} else {
					goDeeper(action, view, listOfMulticatalogs, result, node, pathElements, pointer + 1, refreshTree);
				}
			}
		}
	}

	private static void setSelectionOnTree(final Action action, final StorageBrowserView view, List<String> listOfMulticatalogs,final SearchResult result, final Node node, boolean refreshTree) {
		Node selectedNode = node;
		if (node instanceof CatalogNode && 
				!node.getRootNode().areStoragesVisible() &&
				((CatalogNode) node).getMultiplyCatalogNode() != null) {
			System.out.println("Set selection multi" + node.getPath());
			selectedNode = ((CatalogNode) node).getMultiplyCatalogNode();
			if (!listOfMulticatalogs.contains(node.getPath())) {
				listOfMulticatalogs.add(node.getPath());
				result.setPrimary(true);
			} else if (!result.isPrimary()) {
				// Try find next result witch is not merged in this MultiCatalog
				PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
					@Override
					public void run() {
						action.run();
					}
				});
			}
		}
		System.out.println("Set selection " + node.getPath());
		final ISelection selection = new StructuredSelection(Arrays.asList(selectedNode));
		// We add some new nodes, so we are in new thread
		if (refreshTree) {
			PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
				@Override
				public void run() {
					System.out.println("async");
					view.getTreeViewer().setSelection(selection);
  				view.getTreeViewer().refresh();
  				expandParent(view, node);
				}
			});
		} else {
			System.out.println("sync");
			view.getTreeViewer().setSelection(selection);
			expandParent(view, node);
		}
  }

	private static void expandParent(StorageBrowserView view, Node node) {
		Node parent = node.getParent();
		if (parent instanceof CatalogNode && 
				!parent.getRootNode().areStoragesVisible() &&
				((CatalogNode) parent).getMultiplyCatalogNode() != null) {
				parent = ((CatalogNode) parent).getMultiplyCatalogNode();
		}
		view.getTreeViewer().expandToLevel(parent, 1);
  }
}
